package server

import (
	"context"
	"encoding/json"
	"git.huoys.com/middle-business/xds/internal/model"
	v2 "github.com/envoyproxy/go-control-plane/envoy/api/v2"
	core "github.com/envoyproxy/go-control-plane/envoy/api/v2/core"
	listener "github.com/envoyproxy/go-control-plane/envoy/api/v2/listener"
	hcm "github.com/envoyproxy/go-control-plane/envoy/config/filter/network/http_connection_manager/v2"
	"github.com/envoyproxy/go-control-plane/pkg/cache"
	"github.com/golang/protobuf/proto"
	"github.com/golang/protobuf/ptypes/any"
	_struct "github.com/golang/protobuf/ptypes/struct"
	"google.golang.org/grpc/peer"
	"log"
	"time"
)

func (s *Server) FetchListeners(context.Context, *v2.DiscoveryRequest) (*v2.DiscoveryResponse, error) {
	panic("Not implemented")
}

func (s *Server) StreamListeners(stream v2.ListenerDiscoveryService_StreamListenersServer) error {
	clientPeer, ok := peer.FromContext(stream.Context())
	clientIP := "unknown"
	if ok {
		clientIP = clientPeer.Addr.String()
	}
	log.Printf("[%s] -------------- Starting a %s stream from %s ------------------\n", model.SUBSCRIBE_LDS, model.SUBSCRIBE_LDS, clientIP)

	for {
		req, err := stream.Recv()
		if err != nil {
			log.Println("[StreamListeners] Recv fail, msg: ", err.Error())
			return err
		}
		log.Printf("[StreamListeners] recv version %s ResourceNames %s TypeUrl %s", req.VersionInfo, req.ResourceNames, req.TypeUrl)

		resp :=  &v2.DiscoveryResponse{VersionInfo: model.VERSION, TypeUrl: cache.ListenerType}
		stru := &_struct.Struct{}
		manager := hcm.HttpConnectionManager{
			StatPrefix: "ingress_http",
			CodecType: hcm.HttpConnectionManager_AUTO,
			RouteSpecifier: &hcm.HttpConnectionManager_Rds{
				Rds: &hcm.Rds{RouteConfigName: "local_route", ConfigSource: &core.ConfigSource{
					ResourceApiVersion: core.ApiVersion_V2,
					ConfigSourceSpecifier: &core.ConfigSource_ApiConfigSource{ApiConfigSource: &core.ApiConfigSource{
						ApiType: core.ApiConfigSource_GRPC,
						GrpcServices: []*core.GrpcService{{TargetSpecifier: &core.GrpcService_EnvoyGrpc_{EnvoyGrpc: &core.GrpcService_EnvoyGrpc{ClusterName: "xds-cluster"}}}},
					}},
				}},
			},
			HttpFilters: []*hcm.HttpFilter{
				{Name: "envoy.filters.http.router", ConfigType: &hcm.HttpFilter_Config{}},
			},
		}
		marshal, err := json.Marshal(manager)
		err = stru.UnmarshalJSON(marshal)
		if err != nil {
			log.Println("UnmarshalJSON fail, msg ", err.Error())
		}
		listener := &v2.Listener{
			Name: "listener_0",
			Address: &core.Address{Address: &core.Address_SocketAddress{SocketAddress: &core.SocketAddress{Address: "127.0.0.1", PortSpecifier: &core.SocketAddress_PortValue{PortValue: 80}}}},
			FilterChains: []*listener.FilterChain{{Filters: []*listener.Filter{{Name: "envoy.http_connection_manager", ConfigType: &listener.Filter_Config{Config: stru}}}}},

		}
		bytes, err := proto.Marshal(listener)
		a := &any.Any{
			TypeUrl: cache.ListenerType,
			Value: bytes,
		}
		resp.Resources = []*any.Any{a}
		log.Println("[StreamListeners] resp: ", resp)
		stream.Send(resp)
		time.Sleep(time.Minute)
	}
}
